'''
facade.py

Copyright 2009 Xavier Mendez Navarro aka Javi

This file is part of pysqlin

pysqlin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.

pysqlin is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with pysqlin; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
'''
from framework.ModuleManager import ModuleMan
from framework.proxies import Filters
from framework.proxies import Injectors
from framework.proxies import Plugins
from framework.dispatcher import EventDispatcher
from patterns.singleton import Singleton
from framework.mymodel import DataModel
from framework.mymodel import InjectionData
from framework.settings import Settings
from framework.myexceptions import MyException

import logging
import copy

FILTERS_DIR = 'filters'
INJECTORS_DIR = 'injectors'
PLUGINS_DIR = 'plugins'

class Facade:
    __metaclass__ = Singleton

    def __init__(self):
	self.__logger = logging.getLogger("framework.facade")

	self.sessions = []

	self.__controller = None
	self.__view = None

	self.__ehand = EventDispatcher()

	self.__filters = Filters()
	self.__injectors = Injectors()
	self.__plugins = Plugins()

	ModuleMan(self.__filters, Settings().path_to_program_dir(), FILTERS_DIR)
	ModuleMan(self.__injectors, Settings().path_to_program_dir(), INJECTORS_DIR, False)
	ModuleMan(self.__plugins, Settings().path_to_program_dir(), PLUGINS_DIR)

	self.__cur_session = DataModel(0)
	self.add_session(self.__cur_session)

	if Settings().get(Settings.SEC_GRL, Settings.AUTO_SESSION) == 'True':
	    try:
		self.load_session()
	    except MyException:
		pass

    def startup(self, view, controller):
	self.__controller = controller
	self.__view = view

    # ------------------------------------------------
    # Proxy objects
    # ------------------------------------------------
    def get_injectors(self):
	return self.__injectors

    def get_plugins(self):
	return self.__plugins

    def get_filters(self):
	return self.__filters

    def get_session(self):
	return self.__cur_session

    def get_controller(self):
	return self.__controller

    # ------------------------------------------------
    # session management
    # ------------------------------------------------
    def save_session(self, filename = None):
	if filename is None:
	    filename = Settings().get(Settings.SEC_GRL, Settings.AUTO_SAVE_FILE)
	self.__logger.debug('save_session. START filename=%s', filename)
	self.__cur_session.filters_data.update(self.__filters.filters)


	self.__cur_session.save(filename)


    def load_session(self, path = None):
	self.__logger.debug('load_session. START path=%s', path)

	if not path:
	    path = Settings().get(Settings.SEC_GRL, Settings.AUTO_SAVE_FILE)

	tmp = self.__cur_session.load(path)
	tmp.inj_data.merge_session(self.__cur_session.inj_data)
	tmp.id = self.__cur_session.id
	self.__cur_session = self.subst_session(tmp)

    def subst_session(self, s):
	s.filters_data.merge(self.__filters.filters)
	self.__filters.merge_sett(s.filters_data)

	self.sessions[s.id] = s

	return s

    def add_session(self, s):
	s.filters_data.merge(self.__filters.filters)
	self.__filters.merge_sett(s.filters_data)
	s.inj_data.merge_session(self.__cur_session.inj_data)

	self.sessions.append(s)

	return s

    def list_sessions(self):
	l = []

	i = 0
	for s in self.sessions:
	    if i == self.__cur_session.id:
		l.append(["*" + str(i), s.inj_data[InjectionData.URL], s.inj_data[InjectionData.DATABASE]])
	    else:
		l.append([str(i), s.inj_data[InjectionData.URL], s.inj_data[InjectionData.DATABASE]])
	    i += 1

	return l

    def get_session_ids(self):
	l = []
	for s in self.sessions:
	    l.append(str(s.id))

	return l

    def interact_session(self, id):
	try:
	    s = self.sessions[id]
	    s.id = id
	    s.inj_data.merge_session(self.__cur_session.inj_data)
	    self.__cur_session = s
	except IndexError:
	    raise MyException("Unknown session identifier!")

    def remove_session(self, id):
	if id == self.__cur_session.id:
	    raise MyException("You cannot remove current session")

	try:
	    del(self.sessions[id])
	    self.__cur_session.id = self.sessions.index(self.__cur_session)
	except IndexError:
	    raise MyException("Unknown session identifier!")

    def new_session(self):
	self.__cur_session = self.add_session(DataModel(len(self.sessions)))

    def clone_session(self):
	s = copy.deepcopy(self.__cur_session)

	s.id = len(self.sessions)

	self.__cur_session = self.add_session(s)

    # ------------------------------------------------
    # plugin management
    # ------------------------------------------------
    def delete_plugin_cmds(self):
	self.__view.delete_commands("root", 'plugin')

    def load_plugin(self, plugin):
	self.delete_plugin_cmds()
	self.__cur_session.inj_data.merge_plugin(plugin)

	for name, help, usage, params, functor in plugin.commands():
	    self.add_command(name, help, usage, params, functor)

	plugin.init()

    def get_injector(self):
	job_man = None
	inj_data = self.__cur_session.inj_data

	try:
	    job_man = self.__injectors.get(inj_data[InjectionData.INJECTOR])
	    job_man.check_parameters(inj_data)
	except KeyError, e:
	    self.__logger.error("make_injection. Using an unknown plugin: %s.", e)
	    raise MyException("Exception: Unknown injector")
	except Exception, e:
	    self.__logger.error('make_injection. EXCEPTION: %s' % e)
	    raise MyException("Unhandled exception.")

	return job_man

    def load_injector(self, injector_name):
	injector = self.__injectors.get(injector_name)

	self.__cur_session.inj_data.delete('injectors')
	Facade().get_session().inj_data.merge('injectors', injector.parameters())

    # ------------------------------------------------
    # event handling
    # ------------------------------------------------
    def add_command(self, command_name, help, usage, parameters, functor):
	msg = 'COMMAND ' + 'root.' + command_name
	#self.create_event(msg)
	self.__view.add_command('root', command_name, help, usage, parameters, 'plugin')
	self.__ehand.subscribe(functor, msg)

    def notify(self, msg, **event):
	return self.__ehand.notify(msg, **event)

    def create_event(self, msg):
	self.__ehand.create_event(msg)

    def subscribe(self, func, msg, dynamic = False):
	self.__ehand.subscribe(func, msg, dynamic)

